package cn.tedu.charging.order.amqp;

import cn.tedu.charging.common.constant.AmqpComponentConst;
import cn.tedu.charging.common.pojo.message.DelayCheckMessage;
import cn.tedu.charging.order.mqtt.MqttContext;
import cn.tedu.charging.order.service.ConsumerService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class AmqpConsumer {

    @Autowired
    private ConsumerService consumerService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MqttContext mqttContext;

    //监听 延迟死信队列 获取延迟消息
    //1.单独接收方法入参
    //1.1 接收消息体 反序列化结果
    //1.2 接收完整消息对象
    //1.3 接收底层短连接
    //1.4 组合接收(使用组合)
    @RabbitListener(queues = AmqpComponentConst.DELAY_BILL_DL_QUEUE)
    public void consume(DelayCheckMessage msg, Message message, Channel channel){
        //1.添加抢锁逻辑
        String lockKey="charging:order:lock:"+msg.getOrderNo();
        ValueOperations stringOps = redisTemplate.opsForValue();
        //2.setnx 5秒自动超时时间
        boolean haveLock=false;
        int count=0;
        try{
            do{
                count++;//第一次抢 count==1 2 3 4 第四次最高了
                if (count>1&&count<=4){
                    //不是第一次抢
                    Thread.sleep(1000);
                }else if(count>4){
                    //5,6,7不让抢 消费结束了
                    return;
                }
                haveLock=stringOps.setIfAbsent(lockKey,"",5, TimeUnit.SECONDS);
            }while (!haveLock);
            //调用业务代码 处理业务逻辑
            consumerService.setMqttContext(mqttContext);
            consumerService.handleCheckNoRes(msg);
            //业务处理完毕之后,手动确认反馈
        }catch (Exception e){
            log.error("抢锁执行业务异常",e);
        }finally {
            redisTemplate.delete(lockKey);
        }

        try{
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }catch ( Exception e ){
            log.error("消息确认失败",e);
        }
    }
}
